package model

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"math"
	"math/rand"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"fmt"
	"hash"

	"github.com/capitalone/fpe/ff3"
	"gopkg.in/yaml.v3"
)

//智能脱敏配置规则
type EncryptRule struct {
	Id          int64  `xorm:"pk autoincr"`
	Name        string `xorm:"unique"`
	Title       string
	Description string
	Matcher     string
	Encrypter   *Encrypter `xorm:"json"`
	Disabled    bool       //默认为启动状态，加强防护
	matcher     *regexp.Regexp
}

func (e *EncryptRule) SupportDecrpt() bool {
	return e.Encrypter.ViseVersa()
}

func (e *EncryptRule) Init() {
	if e.Matcher == "!!number" {
		e.matcher = regexp.MustCompile(`^-?[0-9][0-9\.]+$`)
	} else {
		e.matcher = regexp.MustCompile(e.Matcher)
	}
	e.Encrypter.Encrypter.Init()
}

func (e *EncryptRule) Match(value interface{}) bool {
	if e.Matcher == "!!number" {
		switch value.(type) {
		case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
			return true
		}
	}
	switch tv := value.(type) {
	case string:
		return e.matcher.MatchString(tv)
	default:
		return e.matcher.MatchString(fmt.Sprintf("%v", tv))
	}
}

func (e *EncryptRule) Handle(value interface{}) (interface{}, error) {
	return e.Encrypter.Encrypter.Handle(value)
}

func (e *EncryptRule) HandleVersa(value interface{}) (interface{}, error) {
	return e.Encrypter.Decrypter.HandleVersa(value)
}

// 哈希：
// MD5：一种被广泛使用的密码散列函数，可以产生出一个128位（16字节）的散列值。
// SHA1：一种密码散列数，可以生成一个被称为消息摘要的160位（20字节）散列值。
// SHA256：使用的哈希值长度是256位。
// HMAC：基于Hash函数和密钥进行消息认证。
// 遮掩：
// 全遮掩：对整个数据进行脱敏。
// 例如，对手机号码1381111****进行全遮掩，设置遮掩字符串为***********，则脱敏结果为***********。

// 固定位置遮掩：对字段的固定位置进行脱敏处理。
// 例如，对IP地址192.168.255.254的第2段号码进行遮掩，设置遮掩字符串为***，遮掩位置为(5,7)，则脱敏结果为192.***.255.254。

// 固定字符遮掩：对字段的固定字符进行脱敏处理。
// 例如，对邮箱username@example.com中的example进行遮掩，设置遮掩字符串为*******，待遮掩字符串为example，则脱敏结果为username@*******.com。

// 替换：
// 映射替换：将目标字符串替换为设置的字符串。
// 说明
// 多个字符串之间用半角逗号（,）分开。
// 目标字符串中的字符串数量需要与替换字符串中的字符串数量相等。
// 例如，将字符串abcd中的ab替换为mn，设置目标字符串为ab，替换字符串为mn，则脱敏结果为mncd。

// 随机替换：将字段的固定位置，替换为设置的随机字符。
// 例如，对邮箱username@example.com中的username进行随机替换，设置替换位置为(1,8)，随机字符为abc，其中的一个脱敏结果为acbbbbac@example.com。

// 说明 如果随机字符的个数大等于2，脱敏结果不唯一，是随机的。
// 变换：
// 数字取整：保留小数点前第几位。
// 例如，原始数据为1234.12，设置保留小数点前第2位，则脱敏结果为1230。

// 日期取整：日期取整级别。
// 例如，原始数据为2021-10-14 15:15:30，设置日期取整级别为hour，则脱敏结果为2021-10-14 15:00:00。

// 字符位移：字符串循环左移几位。
// 例如，原始数据为345678，设置字符串左移位数为2，则循环左移后的脱敏结果为567834。

// 加密：
// DES：采用DES算法进行加密，密钥长度为8字符，脱敏结果为16字符。
// AES：一种比DES安全的加密方式，密钥长度为16字符，脱敏结果为32字符。

type Encrypter struct {
	Type      int32
	Encrypter EncrypHandler
	Decrypter DecrptHandler
}

func (s *Encrypter) ViseVersa() bool {
	switch s.Type {
	case Encrpt_SubType_Replace_FPE:
		return true
	default:
		return false
	}
}

func (s *Encrypter) Valid() bool {
	switch s.Type {
	case Encrpt_SubType_Hash_Sha1,
		Encrpt_SubType_Hash_Sha256,
		Encrpt_SubType_Hash_Hmac,
		Encrpt_SubType_Cover_Full,
		Encrpt_SubType_Cover_ByPos,
		Encrpt_SubType_Cover_ByStr,
		Encrpt_SubType_Replace_Full,
		Encrpt_SubType_Replace_ByStr,
		Encrpt_SubType_Transform_ForFloat,
		Encrpt_SubType_Transform_ForDate,
		Encrpt_SubType_Replace_FPE,
		Encrpt_SubType_Transform_ForStr:
		return s.Encrypter != nil
	default:
		return false
	}
}

func (s *Encrypter) MarshalJSON() ([]byte, error) {
	var err error
	var t struct {
		Type    int32
		Handler json.RawMessage
	}
	t.Type = s.Type
	t.Handler, err = json.Marshal(s.Encrypter)
	if err != nil {
		return nil, err
	}
	return json.Marshal(&t)
}

func (s *Encrypter) UnmarshalYAML(value *yaml.Node) error {
	if value.Kind == yaml.MappingNode {
		for i := 0; i < len(value.Content)-1; i = i + 2 {
			var cont = value.Content[i]
			switch cont.Value {
			case "type":
				value.Content[i+1].Decode(&s.Type)
			}
		}
	}
	switch s.Type {
	case Encrpt_SubType_Hash_Sha1:
		s.Encrypter = new(HashSHA1Encrypter)
	case Encrpt_SubType_Hash_Sha256:
		s.Encrypter = new(HashSHA256Encrypter)
	case Encrpt_SubType_Hash_Hmac:
		s.Encrypter = new(HashHMACEncrypter)
	case Encrpt_SubType_Cover_Full:
		s.Encrypter = new(CoverFullEncrypter)
	case Encrpt_SubType_Cover_ByPos:
		s.Encrypter = new(CoverByPositionEncrypter)
	case Encrpt_SubType_Cover_ByStr:
		s.Encrypter = new(CoverByStrEncrypter)
	case Encrpt_SubType_Replace_Full:
		s.Encrypter = new(ReplacerFullEncrypter)
	case Encrpt_SubType_Replace_ByStr:
		s.Encrypter = new(ReplacerByStrEncrypter)
	case Encrpt_SubType_Replace_FPE:
		s.Encrypter = new(FpeEncrypter)
	case Encrpt_SubType_Transform_ForFloat:
		s.Encrypter = new(TransformForFloat)
	case Encrpt_SubType_Transform_ForDate:
		s.Encrypter = new(TransformForDate)
	case Encrpt_SubType_Transform_ForStr:
		s.Encrypter = new(TransformForString)
	default:
		return errors.New("UNSUPPORT INPUT")
	}
	return value.Decode(s.Encrypter)
}

func (s *Encrypter) UnmarshalJSON(data []byte) error {
	var t struct {
		Type    int32
		Handler json.RawMessage
	}
	err := json.Unmarshal(data, &t)
	if err == nil {
		s.Type = t.Type
		switch t.Type {
		case Encrpt_SubType_Hash_Sha1:
			s.Encrypter = new(HashSHA1Encrypter)
		case Encrpt_SubType_Hash_Sha256:
			s.Encrypter = new(HashSHA256Encrypter)
		case Encrpt_SubType_Hash_Hmac:
			s.Encrypter = new(HashHMACEncrypter)
		case Encrpt_SubType_Cover_Full:
			s.Encrypter = new(CoverFullEncrypter)
		case Encrpt_SubType_Cover_ByPos:
			s.Encrypter = new(CoverByPositionEncrypter)
		case Encrpt_SubType_Cover_ByStr:
			s.Encrypter = new(CoverByStrEncrypter)
		case Encrpt_SubType_Replace_Full:
			s.Encrypter = new(ReplacerFullEncrypter)
		case Encrpt_SubType_Replace_ByStr:
			s.Encrypter = new(ReplacerByStrEncrypter)
		case Encrpt_SubType_Transform_ForFloat:
			s.Encrypter = new(TransformForFloat)
		case Encrpt_SubType_Transform_ForDate:
			s.Encrypter = new(TransformForDate)
		case Encrpt_SubType_Transform_ForStr:
			s.Encrypter = new(TransformForString)
		case Encrpt_SubType_Replace_FPE:
			var fpe = new(FpeEncrypter)
			s.Encrypter = fpe
			s.Decrypter = fpe
		}
		return json.Unmarshal(t.Handler, s.Encrypter)
	}
	return err
}

const (
	Encrpt_Type_Hash int32 = iota + 1
	Encrpt_Type_Cover
	Encrpt_Type_Replace
	Encrpt_Type_Transform
)

const (
	Encrpt_SubType_Hash_Sha1 int32 = Encrpt_Type_Hash<<16 + iota + 1
	Encrpt_SubType_Hash_Sha256
	Encrpt_SubType_Hash_Hmac
)

const (
	Encrpt_SubType_Cover_Full int32 = Encrpt_Type_Cover<<16 + iota + 1
	Encrpt_SubType_Cover_ByPos
	Encrpt_SubType_Cover_ByStr
)

const (
	Encrpt_SubType_Replace_Full int32 = Encrpt_Type_Replace<<16 + iota + 1
	Encrpt_SubType_Replace_ByStr
	Encrpt_SubType_Replace_FPE
)

const (
	Encrpt_SubType_Transform_ForFloat int32 = Encrpt_Type_Transform<<16 + iota + 1
	Encrpt_SubType_Transform_ForDate
	Encrpt_SubType_Transform_ForStr
)

type EncrypHandler interface {
	Init()
	Handle(input interface{}) (interface{}, error)
}

type DecrptHandler interface {
	HandleVersa(input interface{}) (interface{}, error)
}

type HashSHA1Encrypter struct {
}

func (h *HashSHA1Encrypter) Init() {

}

func (h *HashSHA1Encrypter) Handle(input interface{}) (interface{}, error) {
	var str = fmt.Sprintf("%v", input)
	var hash = sha1.New()
	hash.Write([]byte(str))
	bts := hash.Sum(nil)
	return hex.EncodeToString(bts), nil
}

type HashSHA256Encrypter struct {
}

func (h *HashSHA256Encrypter) Init() {

}

func (h *HashSHA256Encrypter) Handle(input interface{}) (interface{}, error) {
	var str = fmt.Sprintf("%v", input)
	var hash = sha256.New()
	hash.Write([]byte(str))
	bts := hash.Sum(nil)
	return hex.EncodeToString(bts), nil
}

type HashHMACEncrypter struct {
	Secret    string
	Mechenism string
}

func (h *HashHMACEncrypter) Init() {

}

func (h *HashHMACEncrypter) Handle(input interface{}) (interface{}, error) {
	var str = fmt.Sprintf("%v", input)
	var low hash.Hash
	if h.Mechenism == "sha256" {
		low = hmac.New(sha256.New, []byte(h.Secret))
	} else {
		low = hmac.New(sha256.New, []byte(h.Secret))
	}
	low.Write([]byte(str))
	bts := low.Sum(nil)
	return hex.EncodeToString(bts), nil
}

type CoverFullEncrypter struct {
	Replacer     string
	RandomSelect bool
}

func (h *CoverFullEncrypter) Init() {
	if h.Replacer == "" {
		h.Replacer = "*"
	}
}

func (h *CoverFullEncrypter) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	var bts = make([]byte, len(str))
	rand.Seed(time.Now().Unix())
	var last = 0
	for k, _ := range []byte(str) {
		var i = 0
		if len(h.Replacer) > 1 {
			if h.RandomSelect {
				i = rand.Intn(len(h.Replacer))
			} else {
				i = last
				last = (last + 1) % len(h.Replacer)
			}
		}
		bts[k] = h.Replacer[i]
	}
	return string(bts), nil
}

type CoverByPositionEncrypter struct {
	Replacer     string
	Locs         [][2]int16
	RandomSelect bool
}

func (h *CoverByPositionEncrypter) Init() {
	if h.Replacer == "" {
		h.Replacer = "*"
	}
}

func (h *CoverByPositionEncrypter) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	var bts = make([]byte, len(str))
	var i = 0
	var last = 0
	for k, s := range []byte(str) {
		if i < len(h.Locs) {
			if k >= int(h.Locs[i][0]-1) && k <= int(h.Locs[i][1]) {
				var j = 0
				if len(h.Replacer) > 1 {
					if h.RandomSelect {
						j = rand.Intn(len(h.Replacer))
					} else {
						j = last
						last = (last + 1) % len(h.Replacer)
					}
				}
				bts[k] = h.Replacer[j]
				if k == int(h.Locs[i][1]-1) {
					i++
				}
				continue
			}
		}
		bts[k] = s
	}
	return string(bts), nil
}

type CoverByStrEncrypter struct {
	Replacer     string
	Strings      []string
	RandomSelect bool
	replacer     *strings.Replacer
	lastIndexes  map[int]map[byte]int
}

func (h *CoverByStrEncrypter) Init() {
	if h.Replacer == "" {
		h.Replacer = "*"
	}
	if len(h.Replacer) == 1 {
		var replacer = make([]string, len(h.Strings)*2)
		for k, v := range h.Strings {
			var builder strings.Builder
			for i := 0; i < len(v); i++ {
				builder.WriteByte(h.Replacer[0])
			}
			replacer[2*k] = v
			replacer[2*k+1] = builder.String()
		}
		h.replacer = strings.NewReplacer(replacer...)
	} else {
		h.lastIndexes = make(map[int]map[byte]int)
		for k, str := range h.Strings {
			var lastInStr = make(map[byte]int)
			for i := len(str); i > 0; i-- {
				if _, ok := lastInStr[str[i-1]]; !ok {
					lastInStr[str[i-1]] = i - 1
				}
			}
			h.lastIndexes[k] = lastInStr
		}
	}
}

func (h *CoverByStrEncrypter) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	if h.replacer != nil {
		return h.replacer.Replace(str), nil
	} else {
		var skip = len(str)
		var skips = make(map[int]int)
		var last = 0
		var bts = make([]byte, len(str))
	loopInStr:
		for i := 0; i < len(str); i = i + skip {
			skip = len(str) - i
			for k, tester := range h.Strings {
				j := 0
				if offset, ok := skips[k]; ok {
					if offset > skip {
						//不需要比较
						skips[k] = offset - skip
						goto finish
					}
				}
				// {
				for ; j < len(tester); j++ {
					if str[i+j] != tester[j] {
						if offset, ok := h.lastIndexes[k][str[i+len(tester)]]; ok {
							skips[k] = len(tester) - offset
						} else {
							skips[k] = len(tester) + 1
						}
						goto finish
					}
				}
				//找到啦
				for iInR := i; iInR < i+j; iInR++ {
					var jOfR = 0
					if len(h.Replacer) > 1 {
						if h.RandomSelect {
							jOfR = rand.Intn(len(h.Replacer))
						} else {
							jOfR = last
							last = (last + 1) % len(h.Replacer)
						}
					}
					bts[iInR] = h.Replacer[jOfR]
				}
				skip = j
				skips = make(map[int]int) //所有已做了的比较都重来
				continue loopInStr
				// }
			finish:
				if skip > skips[k] {
					skip = skips[k]
				}
			}
			for m := 0; m < skip; m++ {
				bts[i+m] = str[i+m]
			}
		}
		return string(bts), nil
	}
}

type ReplacerFullEncrypter struct {
	Replacer string
}

func (h *ReplacerFullEncrypter) Init() {

}

func (h *ReplacerFullEncrypter) Handle(input interface{}) (interface{}, error) {
	return h.Replacer, nil
}

type ReplacerByStrEncrypter struct {
	Strings  map[string]string
	replacer *strings.Replacer
}

func (h *ReplacerByStrEncrypter) Init() {

	var replacer = make([]string, len(h.Strings)*2)
	var i = 0
	for k, v := range h.Strings {
		replacer[2*i] = k
		replacer[2*i+1] = v
		i++
	}
	h.replacer = strings.NewReplacer(replacer...)
}

func (h *ReplacerByStrEncrypter) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	return h.replacer.Replace(str), nil
}

type TransformForFloat struct {
	Fixed int
	base  float64
}

func (h *TransformForFloat) Init() {
	h.base = math.Pow10(-1 * h.Fixed)
}

func (h *TransformForFloat) Handle(input interface{}) (interface{}, error) {
	var fV float64
	switch ti := input.(type) {
	case float64:
		fV = ti
	case float32:
		fV = float64(ti)
	case int, int8, int16, int32, int64:
		fV = float64(reflect.ValueOf(input).Int())
	case uint, uint8, uint16, uint32, uint64:
		fV = float64(reflect.ValueOf(input).Int())
	case string:
		var err error
		fV, err = strconv.ParseFloat(ti, 64)
		if err != nil {
			return nil, err
		}
	default:
		return nil, errors.New("value is not float value")
	}
	if h.Fixed > 0 {
		return json.Number(fmt.Sprintf("%."+strconv.Itoa(h.Fixed)+"f", fV)), nil
	} else {
		fmt.Println(h.base)
		return json.Number(fmt.Sprintf("%.0f", math.Floor(fV/h.base)*h.base)), nil
	}
}

type TransformForDate struct {
	Origin  string
	Formate string
}

func (h *TransformForDate) Init() {

}

func (h *TransformForDate) Handle(input interface{}) (interface{}, error) {
	var fV time.Time
	var err error
	switch ti := input.(type) {
	case *time.Time:
		fV = *ti
	case time.Time:
		fV = ti
	case string:
		fV, err = time.Parse(h.Origin, ti)
		if err != nil {
			return nil, err
		}
	default:
		return nil, errors.New("value is not string or time")
	}
	return fV.Format(h.Formate), nil
}

//从选定的位置获取字符，组成新的字符，并按位设置到新的位置，比如Formate设置为135790246，则按位取原数据拼成新数据
type TransformForString struct {
	Locs         [][2]int16
	Formate      []int
	replacerLocs []int
}

func (h *TransformForString) Init() {
	var realLoc = make([]int, 0)
	for _, v := range h.Locs {
		for i := int(v[0] - 1); i < int(v[1]); i++ {
			realLoc = append(realLoc, i)
		}
	}

	// fmt.Println(realLoc)

	h.replacerLocs = make([]int, len(realLoc))

	for i := len(h.Formate); i < len(realLoc); i++ {
		h.Formate = append(h.Formate, i+1)
	}

	// fmt.Println(h.Formate)

	for k, v := range realLoc {
		if (h.Formate[k]) > len(realLoc) {
			h.replacerLocs[k] = v
		} else {
			h.replacerLocs[k] = realLoc[h.Formate[k]-1]
		}
	}
	// fmt.Println(h.replacerLocs)
}

func (h *TransformForString) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	var bts = make([]byte, len(str))
	var i = 0
	var no = 0
	for k, s := range []byte(str) {
		if i < len(h.Locs) {
			// fmt.Println(k, i, h.Locs[i][0]-1, h.Locs[i][1], k >= int(h.Locs[i][1]-1))
			if k >= int(h.Locs[i][0]-1) && k < int(h.Locs[i][1]) {
				if len(str) > h.replacerLocs[no] {
					// fmt.Println("-", no, h.replacerLocs[no], k, string(str[h.replacerLocs[no]]))
					bts[k] = str[h.replacerLocs[no]]
				}
				no++
				if k == int(h.Locs[i][1]-1) {
					i++
				}
				continue
			}
		}
		bts[k] = s
	}
	// fmt.Println(string(bts))
	return string(bts), nil
}

type FpeEncrypter struct {
	Key   string
	Tweak string

	cipher ff3.Cipher
}

func (h *FpeEncrypter) Init() {
	key := stringToMd5Bytes(h.Key, 32)
	tweak := stringToMd5Bytes(h.Tweak, 8)

	// Create a new FF3 cipher "object"
	// 10 is the radix/base, and 8 is the tweak length.
	FF3, err := ff3.NewCipher(10, key, tweak)
	if err == nil {
		h.cipher = FF3
	}
}

func (h *FpeEncrypter) Handle(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	var prefix, toEncrypt, suffix string
	if len(str) > 2 {
		prefix = str[:2]
		toEncrypt = str[2:]
	} else {
		toEncrypt = str
	}
	if str[len(str)-1] == 'X' || str[len(str)-1] == 'x' {
		suffix = string(str[len(str)-1])
		toEncrypt = toEncrypt[:len(toEncrypt)-1]
	}
	// Call the encryption function on an example SSN
	ciphertext, err := h.cipher.Encrypt(toEncrypt)
	if err != nil {
		return "", err
	}
	return prefix + ciphertext + suffix, nil
}

func (h *FpeEncrypter) HandleVersa(input interface{}) (interface{}, error) {
	var str string
	switch ti := input.(type) {
	case string:
		str = ti
	default:
		str = fmt.Sprintf("%v", ti)
	}
	var prefix, toDecrypt, suffix string
	if len(str) > 2 {
		prefix = str[:2]
		toDecrypt = str[2:]
	} else {
		toDecrypt = str
	}
	if str[len(str)-1] == 'X' || str[len(str)-1] == 'x' {
		suffix = string(str[len(str)-1])
		toDecrypt = toDecrypt[:len(toDecrypt)-1]
	}
	// Call the encryption function on an example SSN
	plaintext, err := h.cipher.Decrypt(toDecrypt)
	if err != nil {
		return "", err
	}
	return prefix + plaintext + suffix, nil
}

func stringToMd5Bytes(s string, size int) []byte {
	h := md5.New()
	h.Write([]byte(s))
	bts := h.Sum(nil)
	if size < len(bts) {
		return bts[:size]
	}
	return bts
}
